﻿using DoNet.Common.Helpers;
using DoNet.Rsa;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Linq;
using WeWork.Entitys;
using WeWork.Entitys.Send;

namespace WeWork.SDK
{
    /// <summary>
    /// 企业微信会话存档中的sdkfileid具有‌唯一性‌。即使同一文件被多次群发，每次传输生成的sdkfileid均不相同。 ‌
    /// 唯一性验证
    /// 企业微信开发文档明确指出，不同会话或不同传输场景下，相同内容的文件会生成不同的sdkfileid。这一机制确保了文件标识的独立性，便于区分和管理。 ‌
    /// 实际应用场景
    /// 在群发场景中，若需判断某条消息是否为群发，可通过以下方式区分：
    /// 1.文件唯一性检查‌：通过sdkfileid可追溯文件来源，同一文件多次发送会生成不同id；
    /// 2.内容一致性验证‌：结合文件内容（如文本、图片数据）与sdkfileid进行比对，可识别重复发送行为。 ‌
    /// </summary>
    public class ChatDataService : IDisposable
    {
        /// <summary>
        /// 调用企业的企业id，例如：wwd08c8exxxx5ab44d，可以在企业微信管理端--我的企业--企业信息查看
        /// </summary>
        public string CorpId = "";
        /// <summary>
        /// 聊天内容存档的AgentId
        /// </summary>
        public string AgentId = "";
        /// <summary>
        /// 聊天内容存档的Secret，可以在企业微信管理端--管理工具--聊天内容存档查看
        /// </summary>
        public string Secret = "";
        /// <summary>
        /// 会话加密私钥
        /// </summary>
        public List<CorpChatEncryptKeys> VerKey = new List<CorpChatEncryptKeys>();
        /// <summary>
        /// 使用代理的请求，需要传入代理的链接。如：socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081.如不使用代理可以设置为空. 支持sock5跟http代理
        /// </summary>
        public string Proxy = "";
        /// <summary>
        /// 使用代理的请求，需要传入代理的链接。如：socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081.如不使用代理可以设置为空. 支持sock5跟http代理
        /// </summary>
        public string Passwd = "";
        /// <summary>
        /// 企业微信SDK
        /// </summary>
        public IntPtr SDK = IntPtr.Zero;
        /// <summary>
        /// 每次拉去会话记录数上限为1000
        /// 调用频率不可超过4000次/分钟。
        /// 所以一次可以拉取的最大记录数为 4000000（4000 * 1000）
        /// 注意：为了防止记录太多爆内存
        /// </summary>
        public int MaxLimit = 4000000;

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="corpid">企业微信ID</param>
        /// <param name="secret">企业微信会话内容存档Secret</param>
        /// <param name="verKey">企业微信会话内容存档 消息加密公钥对应的私钥列表（版本号，私钥）</param>
        /// <param name="proxy">使用代理的请求，需要传入代理的链接。如：socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081.如不使用代理可以设置为空. 支持sock5跟http代理</param>
        /// <param name="passwd">代理账号密码，需要传入代理的账号密码。如 user_name:passwd_123</param>
        public ChatDataService(string corpid, string agentId, string secret, List<CorpChatEncryptKeys> verKey, string proxy = "", string passwd = "")
        {
            this.CorpId = corpid;
            this.AgentId = agentId;
            this.Secret = secret;
            this.VerKey = verKey;
            this.Proxy = proxy;
            this.Passwd = passwd;

            IntPtr sdk = FinanceHelper.NewSdk();

            //企业微信 corpid，secret
            var result = FinanceHelper.Init(sdk, CorpId, Secret);
            if (result == 0)
            {
                this.SDK = sdk;
            }
            else
            {
                LogHelper.Error("ChatDataService", "企业微信-会话内容存档：初始化SDK阶段返回失败。");
            }
        }

        /// <summary>
        /// 获取slice内容
        /// </summary>
        /// <param name="slice"></param>
        /// <returns></returns>
        public string GetContentFromSlice(IntPtr slice)
        {
            int length = FinanceHelper.GetSliceLen(slice);
            if (length > 0)
            {
                var bytes = new byte[length];
                IntPtr contentFromSlice = FinanceHelper.GetContentFromSlice(slice);
                Marshal.Copy(contentFromSlice, bytes, 0, bytes.Length);
                return Encoding.UTF8.GetString(bytes);
            }
            return string.Empty;
        }

        /// <summary>
        /// 循环获取会话记录数据 以及媒体列表
        /// 调用频率不可超过4000次/分钟。
        /// 注：获取会话记录内容不能超过5天，如果企业需要全量数据，则企业需要定期拉取聊天消息。返回的ChatDatas内容为json格式。
        /// </summary>
        /// <param name="seq">本次请求获取消息记录开始的seq值。首次访问填写0，非首次使用上次企业微信返回的最大seq。允许从任意seq重入拉取。Uint64类型，范围0-pow(2,64)-1</param>
        /// <param name="limit">一次调用限制的limit值，不能超过1000.uint32类型</param>
        /// <param name="timeout">超时时长，单位 秒</param>
        /// <returns>消息列表  媒体文件列表 群列表 内部用户列表 外部联系人列表 机器人列表</returns>
        public Tuple<List<ChatMsg>, List<FileData>> GetChatList(long seq = 0, long limit = 1000, long timeout = 300)
        {
            List<ChatMsg> msgList = new List<ChatMsg>(); //会话列表
            List<FileData> mediaList = new List<FileData>();  //资源文件列表

            DateTime startTime = DateTime.Now;
            int pullNumber = 0; //拉取的次数

            while (true)
            {
                var oldCount = msgList.Count;
                if (oldCount <= MaxLimit)
                {
                    var result = GetChatData(seq, limit, timeout);
                    var list1 = result.Item1;//企业微信 会话内容 列表
                    var list2 = result.Item2;//企业微信 资源文件 列表

                    //看看 调用频率不可超过4000次/分钟。
                    pullNumber++;

                    var count = list1.Count;
                    if (count > 0)
                    {
                        foreach (var item in list1)
                        {
                            if (!msgList.Any(x => x.msgid == item.msgid))
                            {
                                msgList.Add(item);
                            }
                        }
                        foreach (var item in list2)
                        {
                            if (!mediaList.Any(x => x.Md5Sum == item.Md5Sum))
                            {
                                mediaList.Add(item);
                            }
                        }

                        if (count == limit)
                        {
                            seq = list1.OrderByDescending(t => t.seq).Select(q => q.seq).FirstOrDefault();
                        }
                        else
                        {
                            //总数 小于 限制拉取的数量时 说明已经拉取完成 不在循环拉取了
                            break;
                        }
                    }
                    else
                    {
                        //总数 为 0 时 说明已经拉取完成 不在循环拉取了
                        break;
                    }

                    DateTime endTime = DateTime.Now;
                    TimeSpan timeDifference = endTime - startTime;
                    double secondsDifference = timeDifference.TotalSeconds;
                    if (secondsDifference < 60)
                    {
                        if (pullNumber >= 4000)
                        {
                            //一分钟之内 达到4000次  暂停剩余秒数
                            System.Threading.Thread.Sleep((60 - (int)secondsDifference) * 1000);
                            pullNumber = 0;
                        }
                    }
                }
                else
                {
                    break;
                }
            }
            return Tuple.Create(msgList, mediaList);
        }
        
        /// <summary>
        /// 获取会话记录数据  以及媒体列表
        /// 调用频率不可超过4000次/分钟。
        /// 注：获取会话记录内容不能超过5天，如果企业需要全量数据，则企业需要定期拉取聊天消息。返回的ChatDatas内容为json格式。
        /// 注：通话记录中的文件都是唯一的sdkfileid，所以在获取通话记录的同时获取MediaData 没有必要分开
        /// </summary>
        /// <param name="seq">本次请求获取消息记录开始的seq值。首次访问填写0，非首次使用上次企业微信返回的最大seq。允许从任意seq重入拉取。Uint64类型，范围0-pow(2,64)-1</param>
        /// <param name="limit">一次调用限制的limit值，不能超过1000.uint32类型</param>
        /// <param name="proxy">使用代理的请求，需要传入代理的链接。如：socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081.如不使用代理可以设置为空. 支持sock5跟http代理</param>
        /// <param name="passwd">代理账号密码，需要传入代理的账号密码。如 user_name:passwd_123</param>
        /// <param name="timeout">超时时长，单位 秒</param>
        /// <returns>消息列表 媒体文件列表</returns>
        public Tuple<List<ChatMsg>, List<FileData>> GetChatData(long seq = 0, long limit = 1000, long timeout = 300)
        {
            if (limit > 1000)
            {
                limit = 1000;
            }

            List<ChatMsg> msgList = new List<ChatMsg>();  //会话列表
            List<ChatUser> useridList = new List<ChatUser>(); //内部用户、外部联系人、机器人列表
            List<FileData> mediaList = new List<FileData>();  //资源文件列表

            var slice = FinanceHelper.NewSlice();
            try
            {
                var result = FinanceHelper.GetChatData(this.SDK, seq, limit, this.Proxy, this.Passwd, timeout, slice);
                if (result == 0)
                {
                    var content = GetContentFromSlice(slice);
                    if (!string.IsNullOrEmpty(content))
                    {
                        var encryptChatData = JsonHelper.JsonToT<ChatResult>(content);
                        if (encryptChatData != null)
                        {
                            if (encryptChatData.errcode == 0)
                            {
                                foreach (var encryptChat in encryptChatData.chatdata)
                                {
                                    ChatMsg chatMsg = new ChatMsg();
                                    chatMsg.seq = encryptChat.seq;

                                    //根据加密此条消息使用的公钥版本号匹配私钥
                                    var verKey = VerKey.Where(x => x.Ver == encryptChat.publickey_ver).FirstOrDefault();
                                    if (verKey != null)
                                    {
                                        if (!string.IsNullOrWhiteSpace(verKey.PrivateKey))
                                        {
                                            var key = Decrypt(verKey.PrivateKey, encryptChat.encrypt_random_key);
                                            if (!string.IsNullOrWhiteSpace(key))
                                            {
                                                string chatJsonStr = string.Empty;
                                                var msgSlice = FinanceHelper.NewSlice();
                                                var deRes = FinanceHelper.DecryptData(key, encryptChat.encrypt_chat_msg, msgSlice);
                                                if (deRes == 0)
                                                {
                                                    chatJsonStr = GetContentFromSlice(msgSlice);
                                                }
                                                FinanceHelper.FreeSlice(msgSlice);

                                                if (!string.IsNullOrWhiteSpace(chatJsonStr))
                                                {
                                                    var chatBase = JsonHelper.JsonToT<ChatBase>(chatJsonStr);
                                                    if (chatBase != null)
                                                    {
                                                        //消息动作，目前有send(发送消息)/recall(撤回消息)/switch(切换企业日志)三种类型。
                                                        chatMsg.action = chatBase.action;
                                                        #region 
                                                        //切换企业日志
                                                        if (chatBase.action == "switch")
                                                        {
                                                            var chatSwitch = JsonHelper.JsonToT<ChatSwitch>(chatJsonStr);
                                                            if (chatSwitch != null)
                                                            {
                                                                chatMsg.msgtime = TimeHelper.GetUnixTimeToDateTime(chatSwitch.time, false);
                                                                chatMsg.userid = chatSwitch.user;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            var sendChat = JsonHelper.JsonToT<ChatSend>(chatJsonStr);
                                                            if (sendChat != null)
                                                            {
                                                                chatMsg.roomid = sendChat.roomid;
                                                                chatMsg.msgtime = TimeHelper.GetUnixTimeToDateTime(sendChat.msgtime, false);
                                                                chatMsg.createdate = DateTime.UtcNow;
                                                                chatMsg.msgtype = sendChat.msgtype;

                                                                FileData fileData = null;

                                                                //媒体数据 保存目录
                                                                string savePath = CorpId + Path.DirectorySeparatorChar + "{0}" + Path.DirectorySeparatorChar + chatMsg.msgtime.ToString("yyyy-") + Path.DirectorySeparatorChar + chatMsg.msgtime.ToString("MM") + Path.DirectorySeparatorChar + chatMsg.msgtime.ToString("dd") + Path.DirectorySeparatorChar + "{1}.{2}";
                                                                switch (sendChat.msgtype)
                                                                {
                                                                    case "revoke": //撤回消息
                                                                        {
                                                                            var chatReCall = JsonHelper.JsonToT<ChatReCall>(chatJsonStr);
                                                                            if (chatReCall != null)
                                                                            {
                                                                                chatMsg.keyid = chatReCall.revoke.pre_msgid;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "text"://文本
                                                                        {
                                                                            var chatText = JsonHelper.JsonToT<ChatText>(chatJsonStr);
                                                                            if (chatText != null)
                                                                            {
                                                                                chatMsg.content = chatText.text.content;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "image"://图片
                                                                        {
                                                                            var chatImage = JsonHelper.JsonToT<ChatImage>(chatJsonStr);
                                                                            if (chatImage != null)
                                                                            {
                                                                                chatMsg.sdkfileid = chatImage.image.sdkfileid;
                                                                                chatMsg.md5sum = chatImage.image.md5sum;
                                                                                chatMsg.filesize = chatImage.image.filesize;
                                                                                if (mediaList.Any(x => x.Md5Sum == chatMsg.md5sum))
                                                                                {
                                                                                    fileData = mediaList.Where(x => x.Md5Sum == chatMsg.md5sum).FirstOrDefault();
                                                                                    if (fileData != null)
                                                                                    {
                                                                                        mediaList.Remove(fileData);
                                                                                    }
                                                                                }
                                                                                mediaList.Add(new FileData() { FileExt = "jpg", Md5Sum = chatMsg.md5sum, SdkFileId = chatMsg.sdkfileid, SavePath = string.Format(savePath, sendChat.msgtype, chatMsg.md5sum, "jpg") });
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "agree"://同意会话聊天内容
                                                                        {
                                                                            var chatAgree = JsonHelper.JsonToT<ChatAgree>(chatJsonStr);
                                                                            if (chatAgree != null)
                                                                            {
                                                                                chatMsg.agree_time = TimeHelper.GetUnixTimeToDateTime(chatAgree.agree.agree_time, false).ToString("yyyy-MM-dd HH:mm:ss:fff");
                                                                                chatMsg.userid = chatAgree.agree.userid;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "disagree"://不同意会话聊天内容
                                                                        {
                                                                            var chatDisAgree = JsonHelper.JsonToT<ChatDisAgree>(chatJsonStr);
                                                                            if (chatDisAgree != null)
                                                                            {
                                                                                chatMsg.agree_time = TimeHelper.GetUnixTimeToDateTime(chatDisAgree.disagree.disagree_time, false).ToString("yyyy-MM-dd HH:mm:ss:fff");
                                                                                chatMsg.userid = chatDisAgree.disagree.userid;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "voice"://语音
                                                                        {
                                                                            var chatVoice = JsonHelper.JsonToT<ChatVoice>(chatJsonStr);
                                                                            if (chatVoice != null)
                                                                            {
                                                                                chatMsg.sdkfileid = chatVoice.voice.sdkfileid;
                                                                                chatMsg.md5sum = chatVoice.voice.md5sum;
                                                                                chatMsg.filesize = chatVoice.voice.voice_size;
                                                                                chatMsg.playlength = chatVoice.voice.play_length;
                                                                                if (mediaList.Any(x => x.Md5Sum == chatMsg.md5sum))
                                                                                {
                                                                                    fileData = mediaList.Where(x => x.Md5Sum == chatMsg.md5sum).FirstOrDefault();
                                                                                    if (fileData != null)
                                                                                    {
                                                                                        mediaList.Remove(fileData);
                                                                                    }
                                                                                }
                                                                                mediaList.Add(new FileData() { FileExt = "amr", Md5Sum = chatMsg.md5sum, SdkFileId = chatMsg.sdkfileid, SavePath = string.Format(savePath, sendChat.msgtype, chatMsg.md5sum, "amr") });
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "video"://视频
                                                                        {
                                                                            var chatVideo = JsonHelper.JsonToT<ChatVideo>(chatJsonStr);
                                                                            if (chatVideo != null)
                                                                            {
                                                                                chatMsg.sdkfileid = chatVideo.video.sdkfileid;
                                                                                chatMsg.md5sum = chatVideo.video.md5sum;
                                                                                chatMsg.filesize = chatVideo.video.file_size;
                                                                                chatMsg.playlength = chatVideo.video.play_length;
                                                                                if (mediaList.Any(x => x.Md5Sum == chatMsg.md5sum))
                                                                                {
                                                                                    fileData = mediaList.Where(x => x.Md5Sum == chatMsg.md5sum).FirstOrDefault();
                                                                                    if (fileData != null)
                                                                                    {
                                                                                        mediaList.Remove(fileData);
                                                                                    }
                                                                                }
                                                                                mediaList.Add(new FileData() { FileExt = "mp4", Md5Sum = chatMsg.md5sum, SdkFileId = chatMsg.sdkfileid, SavePath = string.Format(savePath, sendChat.msgtype, chatMsg.md5sum, "mp4") });
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "card"://名片
                                                                        {
                                                                            var chatCard = JsonHelper.JsonToT<ChatCard>(chatJsonStr);
                                                                            if (chatCard != null)
                                                                            {
                                                                                chatMsg.userid = chatCard.card.userid;
                                                                                chatMsg.keyname = chatCard.card.corpname;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "location"://位置
                                                                        {
                                                                            var chatLocation = JsonHelper.JsonToT<ChatLocation>(chatJsonStr);
                                                                            if (chatLocation != null)
                                                                            {
                                                                                chatMsg.title = chatLocation.location.title;
                                                                                chatMsg.address = chatLocation.location.address;
                                                                                chatMsg.longitude = chatLocation.location.longitude;
                                                                                chatMsg.latitude = chatLocation.location.latitude;
                                                                                chatMsg.zoom = chatLocation.location.zoom;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "emotion"://表情
                                                                        {
                                                                            var chatEmotion = JsonHelper.JsonToT<ChatEmotion>(chatJsonStr);
                                                                            if (chatEmotion != null)
                                                                            {
                                                                                chatMsg.type = chatEmotion.emotion.type;
                                                                                chatMsg.width = chatEmotion.emotion.width;
                                                                                chatMsg.height = chatEmotion.emotion.height;
                                                                                chatMsg.sdkfileid = chatEmotion.emotion.sdkfileid;
                                                                                chatMsg.md5sum = chatEmotion.emotion.md5sum;
                                                                                chatMsg.filesize = chatEmotion.emotion.imagesize;
                                                                                string fileExt = "";
                                                                                switch (chatEmotion.emotion.type)
                                                                                {
                                                                                    case 1:
                                                                                        fileExt = "gif";
                                                                                        break;
                                                                                    case 2:
                                                                                        fileExt = "png";
                                                                                        break;
                                                                                }
                                                                                if (mediaList.Any(x => x.Md5Sum == chatMsg.md5sum))
                                                                                {
                                                                                    fileData = mediaList.Where(x => x.Md5Sum == chatMsg.md5sum).FirstOrDefault();
                                                                                    if (fileData != null)
                                                                                    {
                                                                                        mediaList.Remove(fileData);
                                                                                    }
                                                                                }
                                                                                mediaList.Add(new FileData() { FileExt = fileExt, Md5Sum = chatMsg.md5sum, SdkFileId = chatMsg.sdkfileid, SavePath = string.Format(savePath, "image", chatMsg.md5sum, fileExt) });
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "file"://文件
                                                                        {
                                                                            var chatFile = JsonHelper.JsonToT<ChatFile>(chatJsonStr);
                                                                            if (chatFile != null)
                                                                            {
                                                                                chatMsg.sdkfileid = chatFile.file.sdkfileid;
                                                                                chatMsg.md5sum = chatFile.file.md5sum;
                                                                                chatMsg.filename = chatFile.file.filename;
                                                                                chatMsg.filesize = chatFile.file.filesize;
                                                                                chatMsg.fileext = chatFile.file.fileext;
                                                                                if (mediaList.Any(x => x.Md5Sum == chatMsg.md5sum))
                                                                                {
                                                                                    fileData = mediaList.Where(x => x.Md5Sum == chatMsg.md5sum).FirstOrDefault();
                                                                                    if (fileData != null)
                                                                                    {
                                                                                        mediaList.Remove(fileData);
                                                                                    }
                                                                                }
                                                                                mediaList.Add(new FileData() { FileExt = chatFile.file.fileext, Md5Sum = chatMsg.md5sum, SdkFileId = chatMsg.sdkfileid, SavePath = string.Format(savePath, sendChat.msgtype, chatMsg.md5sum, chatFile.file.fileext) });
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "link"://链接
                                                                        {
                                                                            var chatLink = JsonHelper.JsonToT<ChatLink>(chatJsonStr);
                                                                            if (chatLink != null)
                                                                            {
                                                                                chatMsg.link_url = chatLink.link.link_url;
                                                                                chatMsg.image_url = chatLink.link.image_url;
                                                                                chatMsg.title = chatLink.link.title;
                                                                                chatMsg.description = chatLink.link.description;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "weapp"://小程序消息
                                                                        {
                                                                            var chatWeapp = JsonHelper.JsonToT<ChatWeApp>(chatJsonStr);
                                                                            if (chatWeapp != null)
                                                                            {
                                                                                chatMsg.keyname = chatWeapp.weapp.displayname;
                                                                                chatMsg.username = chatWeapp.weapp.username;
                                                                                chatMsg.title = chatWeapp.weapp.title;
                                                                                chatMsg.description = chatWeapp.weapp.description;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "chatrecord"://会话记录消息
                                                                        {
                                                                            var chatRecord = JsonHelper.JsonToT<ChatRecord>(chatJsonStr);
                                                                            if (chatRecord != null)
                                                                            {
                                                                                chatMsg.title = chatRecord.chatrecord.title;
                                                                                chatMsg.content = JsonHelper.ObjectToJson(chatRecord.chatrecord.item);
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "todo"://待办消息
                                                                        {
                                                                            var chatTodo = JsonHelper.JsonToT<ChatTodo>(chatJsonStr);
                                                                            if (chatTodo != null)
                                                                            {
                                                                                chatMsg.title = chatTodo.todo.title;
                                                                                chatMsg.content = chatTodo.todo.content;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "vote"://投票消息
                                                                        {
                                                                            var chatVote = JsonHelper.JsonToT<ChatVote>(chatJsonStr);
                                                                            if (chatVote != null)
                                                                            {
                                                                                chatMsg.title = chatVote.vote.votetitle;
                                                                                chatMsg.type = chatVote.vote.votetype;
                                                                                chatMsg.keyid = chatVote.vote.voteid;
                                                                                chatMsg.content = string.Join(",", chatVote.vote.voteitem);
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "collect"://填表消息
                                                                        {
                                                                            var chatCollect = JsonHelper.JsonToT<ChatCollect>(chatJsonStr);
                                                                            if (chatCollect != null)
                                                                            {
                                                                                chatMsg.title = chatCollect.collect.title;
                                                                                chatMsg.time = chatCollect.collect.create_time;
                                                                                chatMsg.username = chatCollect.collect.creator;
                                                                                chatMsg.content = JsonHelper.ObjectToJson(chatCollect.collect.details);
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "redpacket"://红包消息
                                                                        {
                                                                            var chatRedPacket = JsonHelper.JsonToT<ChatRedPacket>(chatJsonStr);
                                                                            if (chatRedPacket != null)
                                                                            {
                                                                                chatMsg.type = chatRedPacket.redpacket.type;
                                                                                chatMsg.wish = chatRedPacket.redpacket.wish;
                                                                                chatMsg.totalcnt = chatRedPacket.redpacket.totalcnt;
                                                                                chatMsg.totalamount = chatRedPacket.redpacket.totalamount;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "meeting"://会议邀请消息
                                                                        {
                                                                            var chatMeeting = JsonHelper.JsonToT<ChatMeeting>(chatJsonStr);
                                                                            if (chatMeeting != null)
                                                                            {
                                                                                chatMsg.title = chatMeeting.meeting.topic;
                                                                                chatMsg.starttime = TimeHelper.GetUnixTimeToDateTime(chatMeeting.meeting.starttime, false).ToString("yyyy-MM-dd HH:mm:ss:fff");
                                                                                chatMsg.endtime = TimeHelper.GetUnixTimeToDateTime(chatMeeting.meeting.endtime, false).ToString("yyyy-MM-dd HH:mm:ss:fff");
                                                                                chatMsg.address = chatMeeting.meeting.address;
                                                                                chatMsg.remarks = chatMeeting.meeting.remarks;
                                                                                chatMsg.type = chatMeeting.meeting.meetingtype;
                                                                                chatMsg.meetingid = chatMeeting.meeting.meetingid;
                                                                                chatMsg.status = chatMeeting.meeting.status;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "meeting_notification"://会议控制消息
                                                                        {
                                                                            var chatMeetingNotification = JsonHelper.JsonToT<ChatMeetingNotification>(chatJsonStr);
                                                                            if (chatMeetingNotification != null)
                                                                            {
                                                                                chatMsg.meetingid = chatMeetingNotification.info.meeting_id;
                                                                                chatMsg.content = chatMeetingNotification.info.content;
                                                                                chatMsg.type = chatMeetingNotification.info.notification_type;
                                                                                chatMsg.time = chatMeetingNotification.time;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "docmsg"://在线文档消息
                                                                        {
                                                                            var chatDocMsg = JsonHelper.JsonToT<ChatDocMsg>(chatJsonStr);
                                                                            if (chatDocMsg != null)
                                                                            {
                                                                                chatMsg.title = chatDocMsg.doc.title;
                                                                                chatMsg.link_url = chatDocMsg.doc.link_url;
                                                                                chatMsg.userid = chatDocMsg.doc.doc_creator;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "markdown"://MarkDown格式消息
                                                                        {
                                                                            var chatMarkDown = JsonHelper.JsonToT<ChatMarkDown>(chatJsonStr);
                                                                            if (chatMarkDown != null)
                                                                            {
                                                                                chatMsg.content = chatMarkDown.info.content;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "news"://图文消息
                                                                        {
                                                                            var chatNews = JsonHelper.JsonToT<ChatNews>(chatJsonStr);
                                                                            if (chatNews != null)
                                                                            {
                                                                                chatMsg.content = JsonHelper.ObjectToJson(chatNews.info.item);
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "calendar"://日程消息
                                                                        {
                                                                            var chatCalendar = JsonHelper.JsonToT<ChatCalendar>(chatJsonStr);
                                                                            if (chatCalendar != null)
                                                                            {
                                                                                chatMsg.title = chatCalendar.calendar.title;
                                                                                chatMsg.username = chatCalendar.calendar.creatorname;
                                                                                chatMsg.starttime = TimeHelper.GetUnixTimeToDateTime(chatCalendar.calendar.starttime, false).ToString("yyyy-MM-dd HH:mm:ss:fff");
                                                                                chatMsg.endtime = TimeHelper.GetUnixTimeToDateTime(chatCalendar.calendar.endtime, false).ToString("yyyy-MM-dd HH:mm:ss:fff");
                                                                                chatMsg.address = chatCalendar.calendar.place;
                                                                                chatMsg.remarks = chatCalendar.calendar.remarks;
                                                                                chatMsg.attendeename = string.Join(",", chatCalendar.calendar.attendeename);
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "mixed"://混合消息
                                                                        var chatMixed = JsonHelper.JsonToT<ChatMixed>(chatJsonStr);
                                                                        if (chatMixed != null)
                                                                        {
                                                                            //消息内容。可包含图片、文字、表情等多种消息。Object类型
                                                                            //此处里面包含了文件、图片、视频、语音等消息 媒体资源是否应该下载下来？
                                                                            chatMsg.content = JsonHelper.ObjectToJson(chatMixed.mixed.item);
                                                                            List<IChatMixedBase> mixedItems = new List<IChatMixedBase>();
                                                                            foreach (var item in chatMixed.mixed.item)
                                                                            {
                                                                                switch (item.type)
                                                                                {
                                                                                    case "text":
                                                                                        {
                                                                                            var textModel = JsonHelper.JsonToT<ChatTextDetail>(item.content);
                                                                                            if (textModel != null)
                                                                                            {
                                                                                                mixedItems.Add(new ChatMixedText() { type = item.type, content = textModel });
                                                                                            }
                                                                                        }
                                                                                        break;
                                                                                    case "image":
                                                                                        {
                                                                                            var imageModel = JsonHelper.JsonToT<ChatImageDetail>(item.content);
                                                                                            if (imageModel != null)
                                                                                            {
                                                                                                mixedItems.Add(new ChatMixedImage() { type = item.type, content = imageModel });
                                                                                                if (mediaList.Any(x => x.Md5Sum == imageModel.md5sum))
                                                                                                {
                                                                                                    fileData = mediaList.Where(x => x.Md5Sum == imageModel.md5sum).FirstOrDefault();
                                                                                                    if (fileData != null)
                                                                                                    {
                                                                                                        mediaList.Remove(fileData);
                                                                                                    }
                                                                                                }
                                                                                                mediaList.Add(new FileData() { FileExt = "jpg", Md5Sum = imageModel.md5sum, SdkFileId = imageModel.sdkfileid, SavePath = string.Format(savePath, item.type, imageModel.md5sum, "jpg") });
                                                                                            }
                                                                                        }
                                                                                        break;
                                                                                    case "emotion":
                                                                                        {
                                                                                            var emotionModel = JsonHelper.JsonToT<ChatEmotionDetail>(item.content);
                                                                                            if (emotionModel != null)
                                                                                            {
                                                                                                mixedItems.Add(new ChatMixedEmotion() { type = item.type, content = emotionModel });
                                                                                                string fileExt = "";
                                                                                                switch (emotionModel.type)
                                                                                                {
                                                                                                    case 1:
                                                                                                        fileExt = "gif";
                                                                                                        break;
                                                                                                    case 2:
                                                                                                        fileExt = "png";
                                                                                                        break;
                                                                                                }
                                                                                                if (mediaList.Any(x => x.Md5Sum == emotionModel.md5sum))
                                                                                                {
                                                                                                    fileData = mediaList.Where(x => x.Md5Sum == emotionModel.md5sum).FirstOrDefault();
                                                                                                    if (fileData != null)
                                                                                                    {
                                                                                                        mediaList.Remove(fileData);
                                                                                                    }
                                                                                                }
                                                                                                mediaList.Add(new FileData() { FileExt = fileExt, Md5Sum = emotionModel.md5sum, SdkFileId = emotionModel.sdkfileid, SavePath = string.Format(savePath, "image", emotionModel.md5sum, fileExt) });
                                                                                            }
                                                                                        }
                                                                                        break;
                                                                                    case "file":
                                                                                        {
                                                                                            var fileModel = JsonHelper.JsonToT<ChatFileDetail>(item.content);
                                                                                            if (fileModel != null)
                                                                                            {
                                                                                                mixedItems.Add(new ChatMixedFile() { type = item.type, content = fileModel });
                                                                                                if (mediaList.Any(x => x.Md5Sum == fileModel.md5sum))
                                                                                                {
                                                                                                    fileData = mediaList.Where(x => x.Md5Sum == fileModel.md5sum).FirstOrDefault();
                                                                                                    if (fileData != null)
                                                                                                    {
                                                                                                        mediaList.Remove(fileData);
                                                                                                    }
                                                                                                }
                                                                                                mediaList.Add(new FileData() { FileExt = fileModel.fileext, Md5Sum = fileModel.md5sum, SdkFileId = fileModel.sdkfileid, SavePath = string.Format(savePath, item.type, fileModel.md5sum, fileModel.fileext) });
                                                                                            }
                                                                                        }
                                                                                        break;
                                                                                    case "voice":
                                                                                        {
                                                                                            var voiceModel = JsonHelper.JsonToT<ChatVoiceDetail>(item.content);
                                                                                            if (voiceModel != null)
                                                                                            {
                                                                                                mixedItems.Add(new ChatMixedVoice() { type = item.type, content = voiceModel });
                                                                                                if (mediaList.Any(x => x.Md5Sum == voiceModel.md5sum))
                                                                                                {
                                                                                                    fileData = mediaList.Where(x => x.Md5Sum == voiceModel.md5sum).FirstOrDefault();
                                                                                                    if (fileData != null)
                                                                                                    {
                                                                                                        mediaList.Remove(fileData);
                                                                                                    }
                                                                                                }
                                                                                                mediaList.Add(new FileData() { FileExt = "amr", Md5Sum = voiceModel.md5sum, SdkFileId = voiceModel.sdkfileid, SavePath = string.Format(savePath, item.type, voiceModel.md5sum, "amr") });
                                                                                            }
                                                                                        }
                                                                                        break;
                                                                                    case "video":
                                                                                        {
                                                                                            var videoModel = JsonHelper.JsonToT<ChatVideoDetail>(item.content);
                                                                                            if (videoModel != null)
                                                                                            {
                                                                                                mixedItems.Add(new ChatMixedVideo() { type = item.type, content = videoModel });
                                                                                                if (mediaList.Any(x => x.Md5Sum == videoModel.md5sum))
                                                                                                {
                                                                                                    fileData = mediaList.Where(x => x.Md5Sum == videoModel.md5sum).FirstOrDefault();
                                                                                                    if (fileData != null)
                                                                                                    {
                                                                                                        mediaList.Remove(fileData);
                                                                                                    }
                                                                                                }
                                                                                                mediaList.Add(new FileData() { FileExt = "mp4", Md5Sum = videoModel.md5sum, SdkFileId = videoModel.sdkfileid, SavePath = string.Format(savePath, item.type, videoModel.md5sum, "mp4") });
                                                                                            }
                                                                                        }
                                                                                        break;

                                                                                }
                                                                            }
                                                                            /*
                                                                            {"msgid":"DAQQluDa4QUY0On4kYSABAMgzPrShAE=","action":"send","from":"HeMiao","tolist":["HeChangTian","LiuZeYu"],"roomid":"wr_tZ2BwAAUwHpYMwy9cIWqnlU3Hzqfg","msgtime":1577414359072,"msgtype":"mixed","mixed":{"item":[{"type":"text","content":"{\"content\":\"你好[微笑]\\n\"}"},{"type":"image","content":"{\"md5sum\":\"368b6c18c82e6441bfd89b343e9d2429\",\"filesize\":13177,\"sdkfileid\":\"CtYBMzA2OTAyMDEwMjA0NjIzMDYwMDIwMTAwMDWwNDVmYWY4Y2Q3MDIwMzBmNTliMTAyMDQwYzljNTQ3NzAyMDQ1ZTA1NmFlMjA0MjQ2NjM0NjIzNjY2MzYzNTMyMmQzNzYxMzQ2NDJkMzQ2MjYxNjQyZDM4MzMzMzM4MmQ3MTYyMzczMTM4NjM2NDYxMzczMjY2MzkwMjAxMDAwMjAzMDIwMDEwMDQxMDM2OGI2YzE4YzgyZTY0NDFiZmQ4OWIyNDNlOWQyNDI4MDIwMTAyMDIwMTAwMDQwMBI4TkRkZk2UWTRPRGcxTVRneE5URTFNRGc1TVY4eE1UTTFOak0yTURVeFh6RTFOemMwTVRNek5EYz0aIDQzMTY5NDFlM2MxZDRmZjhhMjEwY2M0NDQzZGUXOTEy\"}"}]}} 
                                                                            */
                                                                            chatMsg.chatMixedItems = mixedItems;
                                                                        }
                                                                        break;
                                                                    case "meeting_voice_call"://音频存档消息
                                                                        {
                                                                            var chatMeetingVoiceCall = JsonHelper.JsonToT<ChatMeetingVoiceCall>(chatJsonStr);
                                                                            if (chatMeetingVoiceCall != null)
                                                                            {
                                                                                chatMsg.keyid = chatMeetingVoiceCall.voiceid;
                                                                                chatMsg.endtime = TimeHelper.GetUnixTimeToDateTime(chatMeetingVoiceCall.meeting_voice_call.endtime, false).ToString("yyyy-MM-dd HH:mm:ss:fff");
                                                                                chatMsg.demofiledata = JsonHelper.ObjectToJson(chatMeetingVoiceCall.meeting_voice_call.demofiledata);
                                                                                chatMsg.sharescreendata = JsonHelper.ObjectToJson(chatMeetingVoiceCall.meeting_voice_call.sharescreendata);
                                                                                chatMsg.sdkfileid = chatMeetingVoiceCall.meeting_voice_call.sdkfileid;
                                                                                chatMsg.md5sum = Guid.NewGuid().ToString();
                                                                                if (mediaList.Any(x => x.Md5Sum == chatMsg.md5sum))
                                                                                {
                                                                                    fileData = mediaList.Where(x => x.Md5Sum == chatMsg.md5sum).FirstOrDefault();
                                                                                    if (fileData != null)
                                                                                    {
                                                                                        mediaList.Remove(fileData);
                                                                                    }
                                                                                }
                                                                                mediaList.Add(new FileData() { FileExt = "mp4", Md5Sum = chatMsg.md5sum, SdkFileId = chatMsg.sdkfileid, SavePath = string.Format(savePath, "video", chatMsg.md5sum, "mp4") });
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "voip_doc_share"://音频共享文档消息
                                                                        {
                                                                            var chatVoipDocShare = JsonHelper.JsonToT<ChatVoipDocShare>(chatJsonStr);
                                                                            if (chatVoipDocShare != null)
                                                                            {
                                                                                chatMsg.keyid = chatVoipDocShare.voipid;
                                                                                chatMsg.sdkfileid = chatVoipDocShare.voip_doc_share.sdkfileid;
                                                                                chatMsg.md5sum = chatVoipDocShare.voip_doc_share.md5sum;
                                                                                chatMsg.filesize = chatVoipDocShare.voip_doc_share.filesize;
                                                                                chatMsg.filename = chatVoipDocShare.voip_doc_share.filename;
                                                                                if (mediaList.Any(x => x.Md5Sum == chatMsg.md5sum))
                                                                                {
                                                                                    fileData = mediaList.Where(x => x.Md5Sum == chatMsg.md5sum).FirstOrDefault();
                                                                                    if (fileData != null)
                                                                                    {
                                                                                        mediaList.Remove(fileData);
                                                                                    }
                                                                                }
                                                                                mediaList.Add(new FileData() { FileExt = Path.GetExtension(chatVoipDocShare.voip_doc_share.filename).Replace(".", ""), Md5Sum = chatMsg.md5sum, SdkFileId = chatMsg.sdkfileid, SavePath = string.Format(savePath, "file", chatMsg.md5sum, Path.GetExtension(chatVoipDocShare.voip_doc_share.filename).Replace(".", "")) });
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "external_redpacket"://互通红包消息
                                                                        {
                                                                            var chatExternalRedPacket = JsonHelper.JsonToT<ChatExternalRedPacket>(chatJsonStr);
                                                                            if (chatExternalRedPacket != null)
                                                                            {
                                                                                chatMsg.type = chatExternalRedPacket.redpacket.type;
                                                                                chatMsg.wish = chatExternalRedPacket.redpacket.wish;
                                                                                chatMsg.totalcnt = chatExternalRedPacket.redpacket.totalcnt;
                                                                                chatMsg.totalamount = chatExternalRedPacket.redpacket.totalamount;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "sphfeed"://视频号消息
                                                                        {
                                                                            var chatSphFeed = JsonHelper.JsonToT<ChatSphFeed>(chatJsonStr);
                                                                            if (chatSphFeed != null)
                                                                            {
                                                                                chatMsg.type = chatSphFeed.sphfeed.feed_type;
                                                                                chatMsg.keyname = chatSphFeed.sphfeed.sph_name;
                                                                                chatMsg.description = chatSphFeed.sphfeed.feed_desc;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "voiptext"://音视频通话
                                                                        {
                                                                            var chatVoipText = JsonHelper.JsonToT<ChatVoipText>(chatJsonStr);
                                                                            if (chatVoipText != null)
                                                                            {
                                                                                chatMsg.type = chatVoipText.info.invitetype;
                                                                                chatMsg.playlength = chatVoipText.info.callduration;
                                                                            }
                                                                        }
                                                                        break;
                                                                    case "qydiskfile"://微盘文件 
                                                                        {
                                                                            var chatQyDiskFile = JsonHelper.JsonToT<ChatQyDiskFile>(chatJsonStr);
                                                                            if (chatQyDiskFile != null)
                                                                            {
                                                                                chatMsg.filename = chatQyDiskFile.info.filename;
                                                                            }
                                                                        }
                                                                        break;
                                                                }

                                                                /*
                                                                机器人与外部联系人的账号都是external_userid，其中机器人的external_userid是以"wb"开头，例如："wbjc7bDwAAJVylUKpSA3Z5U11tDO4AAA"，外部联系人的external_userid以"wo"或"wm"开头。
                                                                如果是机器人发出的消息，可以通过openapi拉取机器人详情：如何获取机器人详情？
                                                                如果是外部联系人发出的消息，可以通过openapi拉取外部联系人详情：如何获取外部联系人详情？ 
                                                                */
                                                                var from = sendChat.from;
                                                                if (!string.IsNullOrWhiteSpace(from))
                                                                {
                                                                    ChatUser chatUser = new ChatUser();
                                                                    chatUser.userid = from;
                                                                    chatUser.isfrom = true;
                                                                    chatUser.usertype = GetUserIsFrom(from);
                                                                    useridList.Add(chatUser);
                                                                }

                                                                var tolist = sendChat.tolist;
                                                                if (tolist != null)
                                                                {
                                                                    foreach (var user in tolist)
                                                                    {
                                                                        ChatUser chatUser = new ChatUser();
                                                                        chatUser.userid = user;
                                                                        chatUser.isfrom = false;
                                                                        chatUser.usertype = GetUserIsFrom(user);
                                                                        useridList.Add(chatUser);
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        #endregion
                                                        if (useridList.Count > 0)
                                                        {
                                                            chatMsg.users = useridList;
                                                        }
                                                        msgList.Add(chatMsg);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                LogHelper.Error("ChatDataService", "企业微信-会话内容存档：会话数据解密失败。");
                                            }
                                        }
                                        else
                                        {
                                            LogHelper.Error("ChatDataService", "企业微信-会话内容存档：会话数据解密私钥为空。");
                                        }
                                    }
                                    else
                                    {
                                        LogHelper.Error("ChatDataService", $"企业微信-会话内容存档：消息加密公钥私钥版本号缺失[{encryptChat.publickey_ver}]。");
                                    }
                                }
                            }
                            else
                            {
                                LogHelper.Error("ChatDataService", $"企业微信-会话内容存档：转换会话数据阶段返回值错误\n[{encryptChatData.errcode}]{encryptChatData.errmsg}");
                            }
                        }
                        else
                        {
                            LogHelper.Error("ChatDataService", $"企业微信-会话内容存档：转换会话数据阶段失败！");
                        }
                    }
                    else
                    {
                        LogHelper.Error("ChatDataService", "企业微信-会话内容存档：获取会话数据内容为空。");
                    }
                }
                else
                {
                    LogHelper.Error("ChatDataService", $"企业微信-会话内容存档：获取会话数据阶段返回失败【{result}】。");
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error("ChatDataService", "企业微信-会话内容存档：获取会话数据数据异常。" + ex.ToString());
            }
            finally
            {
                Finance.FreeSlice(slice);
            }
            return Tuple.Create(msgList, mediaList);
        }
        
        /// <summary>
        /// 读取媒体数据（文件拉取完结才会返回数据，否则返回null）
        /// 针对图片、文件等媒体数据，提供sdk接口拉取数据内容。调用频率不可超过25000次/分钟。
        /// </summary>
        /// <param name="sdkfileid">消息体内容中的sdkfileid信息。</param>
        /// <param name="timeout">超时时间，单位秒</param>
        /// <returns>(errorcode, byte[]) errorcode=0时 文件才算是拉取完结</returns>
        public Tuple<int, byte[]> GetMediaData(string sdkfileid, long timeout = 300)
        {
            /*
            错误码：
            返回值	说明	建议
            10000	请求参数错误	检查Init接口corpid、secret参数；检查GetChatData接口limit参数是否未填或大于1000；检查GetMediaData接口sdkfileid是否为空，indexbuf是否正常
            10001	网络请求错误	检查是否网络有异常、波动；检查使用代理的情况下代理参数是否设置正确的用户名与密码
            10002	数据解析失败	建议重试请求。若仍失败，可以反馈给企业微信进行查询，请提供sdk接口参数与调用时间点等信息
            10003	系统调用失败	GetMediaData调用失败，建议重试请求。若仍失败，可以反馈给企业微信进行查询，请提供sdk接口参数与调用时间点等信息
            10004	已废弃	        目前不会返回此错误码
            10005	fileid错误	    检查在GetMediaData接口传入的sdkfileid是否正确
            10006	解密失败	    请检查是否先进行base64decode再进行rsa私钥解密，再进行DecryptMsg调用
            10007	已废弃	        目前不会返回此错误码
            10008	DecryptMsg错误	建议重试请求。若仍失败，可以反馈给企业微信进行查询，请提供sdk接口参数与调用时间点等信息
            10009	ip非法	        请检查sdk访问外网的ip是否与管理端设置的可信ip匹配，若不匹配会返回此错误码
            10010	请求的数据过期	用户欲拉取的数据已过期，仅支持近5天内的数据拉取
            10011	ssl证书错误	    使用openssl版本sdk，校验ssl证书失败 
            */
            int errorcode = -1; //errorcode=0时 文件才算是拉取完结
            var byteList = new List<byte>();
            try
            {
                var mediaData = FinanceHelper.NewMediaData();
                string outIndexBuf = "";//媒体消息分片拉取，需要填入每次拉取的索引信息。首次不需要填写，后续每次调用只需要将上次调用返回的outindexbuf填入即可。
                while (true)
                {
                    int retryCount = 0;
                    RetryGetMedia:
                    var res = FinanceHelper.GetMediaData(this.SDK, outIndexBuf, sdkfileid, this.Proxy, this.Passwd, timeout, mediaData);
                    if (res == 0)
                    {
                        var dataIntPtr = FinanceHelper.GetData(mediaData);
                        var dataLen = FinanceHelper.GetDataLen(mediaData);
                        var bytes = new byte[dataLen];
                        Marshal.Copy(dataIntPtr, bytes, 0, bytes.Length);
                        byteList.AddRange(bytes);

                        // 校验文件是否已经读取完毕
                        if (Finance.IsMediaDataFinish(mediaData) == 1)
                        {
                            errorcode = res;
                            break;
                        }
                        else
                        {
                            var oibPtr = FinanceHelper.GetOutIndexBuf(mediaData);
                            var oibStr = Marshal.PtrToStringAnsi(oibPtr);
                            if (!string.IsNullOrEmpty(oibStr))
                            {
                                outIndexBuf = oibStr;
                            }
                        }
                    }
                    else
                    {
                        //10001 网络请求错误
                        //10002 解析数据失败
                        //10003 系统调用失败
                        if ((res == 10001 || res == 10002 || res == 10003) && retryCount < 3)
                        {
                            retryCount++;
                            System.Threading.Thread.Sleep(500);
                            goto RetryGetMedia;
                        }
                        else
                        {
                            errorcode = res;
                            //throw new Exception($"企微会话存档:获取会话媒体数据失败，res:{res}");
                            LogHelper.Error("ChatDataService", $"企业微信-会话内容存档：获取会话媒体数据失败，sdkfileid:{sdkfileid};res:{res}");
                            break;
                        }
                    }
                }
                FinanceHelper.FreeMediaData(mediaData);
            }
            catch (Exception ex)
            {
                LogHelper.Error("ChatDataService", "企业微信-会话内容存档：获取会话媒体数据失败！" + ex.ToString());
            }

            if (errorcode == 0)
            {
                if (byteList.Count > 0)
                {
                    return Tuple.Create(errorcode, byteList.ToArray());
                }
            }
            return Tuple.Create(errorcode, new byte[0]);
        }

        /// <summary>
        /// 获取媒体数据列表（含文件byte[]）
        /// 针对图片、文件等媒体数据，提供sdk接口拉取数据内容。调用频率不可超过25000次/分钟。
        /// </summary>
        /// <param name="list">媒体数据列表</param>
        /// <param name="timeout">超时时间，单位秒</param>
        /// <returns></returns>
        public List<FileData> GetFileList(List<FileData> list, long timeout = 300)
        {
            List<FileData> listNew = new List<FileData>();
            if (list.Count > 0)
            {
                DateTime startTime = DateTime.Now;
                int pullNumber = 0; //拉取的次数
                foreach (var file in list)
                {
                    var result = GetMediaData(file.SdkFileId, timeout);
                    if (result.Item1 == 0)
                    {
                        file.FileBytes = result.Item2;
                    }
                    listNew.Add(file);

                    //看看 调用频率不可超过25000次/分钟。
                    pullNumber++;

                    DateTime endTime = DateTime.Now;
                    TimeSpan timeDifference = endTime - startTime;
                    double secondsDifference = timeDifference.TotalSeconds;
                    if (secondsDifference < 60)
                    {
                        if (pullNumber >= 25000)
                        {
                            System.Threading.Thread.Sleep((60 - (int)secondsDifference) * 1000);
                            pullNumber = 0;
                        }
                    }
                }

                list = new List<FileData>();
            }
            return listNew;
        }
        
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="privateKey">私钥 “-----BEGIN RSA PRIVATE KEY-----”开头 “-----END RSA PRIVATE KEY-----”结尾</param>
        /// <param name="text">使用publickey_ver指定版本的公钥进行非对称加密后base64加密的内容</param>
        /// <returns></returns>
        public string Decrypt(string privateKey, string text)
        {
            var bytes = Convert.FromBase64String(text);
            //using (var rsa = new RSACryptoServiceProvider())
            //{
            //    rsa.FromXmlString(RsaHelper.PrivateKeyPemToXml(privateKey));
            //    return Encoding.UTF8.GetString(rsa.Decrypt(bytes, false));
            //}
            return RsaHelper.Decrypt(bytes, privateKey, Encoding.UTF8);
        }

        /// <summary>
        /// 根据userid判断 员工、外部联系人、机器人
        /// 1：员工；2：外部联系人; 3：机器人
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public int GetUserIsFrom(string userid)
        {
            //1：员工；2：外部联系人; 3：机器人
            if (userid.StartsWith("w") && userid.Length > 2 && userid.Length == 32)
            {
                if (userid.StartsWith("wb")) //机器人
                {
                    return 3;
                }
                else
                {
                    //if (userid.StartsWith("wo") || userid.StartsWith("wm")) //外部联系人
                    return 2;
                }
            }
            else  //企业内部人员
            {
                return 1;
            }
        }

        /// <summary>
        /// 自动释放sdk
        /// </summary>
        public void Dispose()
        {
            if (this.SDK != IntPtr.Zero)
            {
                FinanceHelper.DestroySdk(this.SDK);
            }
        }
    }
}
